package xin.yangda.xpoi.xls;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;

import com.alibaba.fastjson.JSONObject;

import xin.yangda.xpoi.util.WordDefined;

/**
 * 根据特定Excel导出Excel文档
 * 
 * @author izifeng
 * @version 1.0
 * @date 2017-12-08 11:03
 * @site https://gitee.com/izifeng/XPOI.git
 *
 */
public class WorkbookDesigner {

	private static final String ROW_IDX = "rowIdx";
	private static final String COL_IDX = "colIdx";
	private static final String CELL_STYLE = "CellStyle";

	// 工作表
	private HSSFWorkbook workBook;

	// 数据源
	private List<JSONObject> dataSource = null;

	// 文档输出流
	private ByteArrayOutputStream os = null;

	// 存储自定义字段
	private HashMap<String, String> map = new HashMap<>();

	public WorkbookDesigner() {
		os = new ByteArrayOutputStream();
	}

	public ByteArrayOutputStream getOs() {
		return os;
	}

	/**
	 * 打开excel模板
	 * 
	 * @param filePath
	 *            excel模板路径
	 * @throws IOException
	 */
	public void open(String filePath) throws IOException {
		if (filePath.trim().toLowerCase().endsWith("xls")) {
			File file = new File(filePath);

			FileInputStream fis = new FileInputStream(file);

			POIFSFileSystem fs = new POIFSFileSystem(fis);

			// 读取excel模板
			workBook = new HSSFWorkbook(fs);
		} else {
			throw new IllegalArgumentException(WordDefined.ONLY_SUPPORT_XLS);
		}
	}

	/**
	 * 添加数据源
	 * 
	 * @param list
	 */
	public void setDataSource(List<JSONObject> list) {
		dataSource = list;
	}

	/**
	 * 添加自定义字段
	 * 
	 * @param key
	 * @param value
	 */
	public void setDataSource(String key, String value) {
		map.put(key, value);
	}

	/**
	 * 数据处理
	 * 
	 * @throws IOException
	 */
	public void process() throws IOException {
		// 获取第一张工作簿
		HSSFSheet sheet = workBook.getSheetAt(0);

		// 获得总列数
		int coloumNum = sheet.getRow(0).getPhysicalNumberOfCells();

		// 获得总行数
		int rowNum = sheet.getLastRowNum();

		// 数据源字段 单元格数据，存储 行、列、单元格样式
		JSONObject dsField = new JSONObject();

		// 自定义数据源字段 单元格数据，存储 行、列
		JSONObject cdsField = new JSONObject();

		// 提取模板中数据源相关字段位置信息，包括：行、列、单元格样式
		for (int rowIdx = 0; rowIdx <= rowNum; rowIdx++) {
			Row row = sheet.getRow(rowIdx);
			for (int colIdx = 0; colIdx < coloumNum; colIdx++) {
				// 获取单元格
				Cell cell = row.getCell(colIdx);

				// 单元格值
				String cellValue = cell.getStringCellValue().trim();

				// 单元格内容不满足模板要求
				if (cellValue.length() == 0 || cellValue.indexOf("&=") != 0)
					continue;

				JSONObject dsJson = new JSONObject();
				dsJson.put(ROW_IDX, rowIdx);
				dsJson.put(COL_IDX, colIdx);
				dsJson.put(CELL_STYLE, cell.getCellStyle());

				if (cellValue.indexOf("&=$") == 0) {// 自定义数据源字段
					String field = cellValue.replace("&=$", "");
					cdsField.put(field, dsJson);
				} else if (cellValue.indexOf("&=") == 0) {// 数据源字段
					String field = cellValue.replace("&=", "");
					dsField.put(field, dsJson);
				}
			}
		}

		// 填充自定义字段
		if (map.size() > 0) {
			fillCustomField(sheet, cdsField);
		}

		// 填充数据
		if (dataSource != null) {
			fillDataSourceField(sheet, dsField);
		}

		workBook.write(os);

		workBook.close();
	}

	/**
	 * 填充自定义字段
	 * 
	 * @param sheet
	 *            工作簿
	 * @param cdsField
	 *            字段信息
	 */
	private void fillCustomField(HSSFSheet sheet, JSONObject cdsField) {
		for (Map.Entry<String, String> entry : map.entrySet()) {
			String key = entry.getKey();
			JSONObject jsonObj = (JSONObject) cdsField.get(key);

			if (jsonObj == null)
				continue;

			// 获取行
			Row row = sheet.getRow(jsonObj.getInteger(ROW_IDX));

			// 获取列
			Cell cell = row.getCell(jsonObj.getInteger(COL_IDX));

			// 填充值
			cell.setCellValue(entry.getValue());
		}
	}

	/**
	 * 填充数据源字段
	 * 
	 * @param sheet
	 *            工作簿
	 * @param dsField
	 *            字段信息
	 */
	private void fillDataSourceField(HSSFSheet sheet, JSONObject dsField) {
		// 获取数据源中第一行数据为基础数据
		JSONObject firstRow = dataSource.get(0);

		// 数据源键值
		Set<String> sKey = firstRow.keySet();

		Iterator<String> iterator = sKey.iterator();
		while (iterator.hasNext()) {
			// 数据源字段名
			String key = iterator.next();

			// 获取excel单元格信息
			JSONObject jsonObj = (JSONObject) dsField.get(key);
			if (jsonObj == null)
				continue;

			// 行号
			int rowIdx = jsonObj.getInteger(ROW_IDX);

			// 列号
			int colIdx = jsonObj.getInteger(COL_IDX);

			// 单元格按时
			CellStyle cellStyle = (CellStyle) jsonObj.get(CELL_STYLE);

			// 填充单元格数据
			for (int i = 0; i < dataSource.size(); i++) {
				// 获取行
				Row row = sheet.getRow(rowIdx + i);

				if (row == null)
					row = sheet.createRow(rowIdx + i);

				// 获取列
				Cell cell = row.getCell(colIdx);

				if (cell == null)
					cell = row.createCell(colIdx);

				// 设置单元格样式
				cell.setCellStyle(cellStyle);

				// 填充单元格数据
				JSONObject json = dataSource.get(i);

				cell.setCellValue(json.getString(key));
			}
		}
	}

	/**
	 * 保存文件
	 * 
	 * @param filePath
	 *            目标文件路径
	 * @throws IOException
	 */
	public void saveFile(String filePath) throws IOException {
		byte[] content = os.toByteArray();

		InputStream is = new ByteArrayInputStream(content);

		FileOutputStream outputStream = new FileOutputStream(filePath);

		BufferedInputStream bis = new BufferedInputStream(is);

		BufferedOutputStream bos = new BufferedOutputStream(outputStream);

		byte[] buff = new byte[8192];

		int bytesRead;

		while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
			bos.write(buff, 0, bytesRead);
		}

		bis.close();

		bos.close();

		outputStream.flush();

		outputStream.close();
	}
}
